/**

This file is part of MaCI/GIMnet.

MaCI/GIMnet is free software: you can redistribute it and/or modify it 
under the terms of the GNU Lesser General Public License as published 
by the Free Software Foundation, either version 3 of the License, or 
(at your option) any later version.

MaCI/GIMnet is distributed in the hope that it will be useful, but WITHOUT 
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public 
License for more details.

You should have received a copy of the GNU Lesser General Public 
License along with GIMnet. (See COPYING.LESSER) If not, see 
<http://www.gnu.org/licenses/>.

**/
// -*- coding:iso-8859-15 mode: c++ -*-
/** 
 * \file
 * \brief MaCI_Image Player for logged files.
 * \author Matthieu Myrsky <matthieu.myrsky@tkk.fi>
 *
 * $Id: ImageFilePlayer.cpp,v 1.11 2009-11-13 15:11:18 morsko Exp $
 *
 */

#include "ImageFilePlayer.hpp"
#include <stdlib.h> 
//#include <iostream.h> 
#include <string>
ImageFilePlayer::ImageFilePlayer( MaCI::Image::CImageServer *aImageServer,
                                  std::string aFileName)
  :PlayerModule(),
   iImageServer(aImageServer),
   iData(),
   iImageInfos(),
   iTimes(),
   iBegin(0,0),
   iEnd(0,0),
   iDirectory(),
   iFile(NULL),
   iName(""),
   iImageFormat(MaCI::Image::KImageDataUnknown),
   iImageCount(0)
{
 
  
  dPrint(3,"Opening file '%s'",aFileName.c_str());
  iFile= fopen(aFileName.c_str(),"rt");

  char c[200];
  std::string instanceName;
  //  char d[200];

   memset(iDirectory,'\0',512);

  //Directory name for image files are the same than the log file without '.txt'
   aFileName.copy(iDirectory,aFileName.size()-4);

  //Read the seven first lines..and get the instanceacename...
  fgets (c, 200,iFile );
  fgets (c, 200,iFile );

  std::string s1(c);
  std::string::size_type begin;
  std::string::size_type end;
  begin = s1.find("Instance:");
  end = s1.find("\n");
  dPrint(1,"Begin %u, end %u",begin, end);
  if(begin == std::string::npos || end == std::string::npos){
    dPrint(1,"did not found instance name... ERRROR!");
    return;
  }else{
    //Remove the linechange at the end...
    instanceName = s1.substr(begin+10, end-begin-10);
  }
  

  //  fscanf(iFile,"%s %s %s %s",c,c,c,instanceName);
  fgets (c, 200,iFile );

  std::string s2(c);
  begin = std::string::npos;
  begin = s2.find("image_format:");
  end = s2.find("image_count:");

  if(begin == std::string::npos && end == std::string::npos){
   
    //Just to support old logFiles..
    iImageFormat = MaCI::Image::KImageDataJPEG;
    iImageCount = 1;
  }else if(begin == std::string::npos && end != std::string::npos){
    iImageFormat = MaCI::Image::KImageDataUnknown;
    std::string imagecount = s2.substr(end+13);
    iImageCount = atoi(imagecount.c_str());
  }else{
    
    //    dPrint(1,"begin %d, length %d",begin,end -begin);
    std::string imageformat= s2.substr(begin+14,end-(begin+14));
    iImageFormat = (MaCI::Image::EImageDataType)atoi(imageformat.c_str());
    //dPrint(1,"%s",imageformat.c_str());
    std::string imagecount = s2.substr(end+13);
    iImageCount = atoi(imagecount.c_str());
  }
  /*  while(cont){
    
    numberRead = sscanf(c,"%s ",d);
    dPrint(1,"numberRead = %d d='%s'",numberRead,d);
    if(numberRead != 1){
      break;
    }
    std::string s(d);
    if(s.compare("image_format:") == 0){
      imageFormatTextFound = true;
    }

    if(s.compare("image_count:") == 0){
      imageCountTextFound = true;
    }

    if(imageFormatTextFound && !imageFormatSaved){
      scanf(d,"%d",&iImageFormat);
      imageFormatSaved = true;
    }

    if(imageCountTextFound){
      scanf(d,"%d",&iImageCount);
      cont = false;
    }


  }
  */
  //int numberRead = sscanf(c,"%s %s %s %u %s %u",d,d,d,(unsigned int*)&iImageFormat,d,&iImageCount);
  //dPrint(1,"numberRead %d",numberRead);
  // dPrint(1,"imageFormat %d",iImageFormat);
  //dPrint(1,"imageCount %d",iImageCount);
  //dPrint(1,"directory %s",iDirectory);
 

  // dPrint(1,"Got %d for imageFormat and %d for imageCount, directory: %s",iImageFormat,iImageCount,iDirectory);
  fgets (c, 200,iFile );
  //dPrint(1,"c = %s",c);
  fgets (c, 200,iFile );
  //dPrint(1,"c = %s",c);
  fgets (c, 200,iFile );  
  //dPrint(1,"c = %s",c);

 
  iImageServer->SetInterfaceInstanceName(instanceName);
  iImageServer->Open();

  iName = "MaCI_Image."+instanceName;
  dPrint(1,"Got for image file directory :'%s'. Also set '%s' for instance name",iDirectory,instanceName.c_str());
  ReadData();
}
//*****************************************************************************

ImageFilePlayer::~ImageFilePlayer()
{
  fclose(iFile);
  delete(iImageServer);
}
//*****************************************************************************

bool ImageFilePlayer::ReadData()
{
  using namespace MaCI::Image;
  MaCI::Common::TTimestamp timestamp;
  unsigned int fileSize;
  int number = 1;
  bool first = true;
  unsigned int format;
  unsigned int width,height;
  while(number != 0 && number != EOF){
    std::vector<unsigned int> dataSizeList;
    std::vector<MaCI::Image::TImageInfo> infos;
    number = fscanf(iFile,"%u %u ",
                    &(timestamp.timestamp_s),
                    &(timestamp.timestamp_us));
    if(number != EOF){
      for(unsigned int i = 0; i< iImageCount; i++){
        if(iImageFormat ==  MaCI::Image::KImageDataJPEG){
          number += fscanf(iFile,"%u",
                           &fileSize);
          
          dataSizeList.push_back(fileSize);
          infos.push_back(MaCI::Image::TImageInfo(0,0 ,MaCI::Image::KImageDataJPEG,0));
        }else{
          number += fscanf(iFile,"%u %u %u %u",
                           &fileSize,
                           &format,
                           &width,
                           &height);
          dataSizeList.push_back(fileSize);
          infos.push_back(MaCI::Image::TImageInfo(width,height ,(MaCI::Image::EImageDataType)(format),0));

        }
        if(first && number >= 3){
          
          iBegin = timestamp.GetGimTime();
          
          first = false;
        }    
      }
    }
    if(number> 0){
      
      //Open the file 
      
      iData[timestamp.GetGimTime()] = dataSizeList;
      iImageInfos[timestamp.GetGimTime()] = infos;

      iTimes.push_back(timestamp.GetGimTime());
    }
    
  
    ownSleep_ms(1);

  }
    if(!first){
      iEnd = timestamp.GetGimTime();
      dPrint(1,"Got first time %d %d, last %d %d",iBegin.seconds,iBegin.useconds,iEnd.seconds,iEnd.useconds);
    }
  if(number == EOF){
    return true;
  }else{
    return false;
  }
}
//*****************************************************************************

bool ImageFilePlayer::OnTime(gim::time aTime)
{
  using namespace MaCI::Image;
  CImageData id;
  CImageContainer idc;
  static char buffer[4096 * 1000];
  MaCI::Common::TTimestamp timestamp(aTime);
  int b;
  int r;
  MaCI::EMaCIError e;
  /**/
  char wholeFileName[512];

  /**/
  // Create backend.
  r= id.CreateInternalBinBag();
  
  std::map<gim::time,std::vector<unsigned int> >::iterator iter
    =iData.find(aTime);

  std::map<gim::time,std::vector<MaCI::Image::TImageInfo> >::iterator imageInfoIter
    =iImageInfos.find(aTime);
  if(iter != iData.end() && imageInfoIter != iImageInfos.end()){
    //Construct image
    id.SetTimestamp(timestamp); // Set timestamp
  
  


    for(unsigned int i = 0; i< iImageCount; i++){

      if(imageInfoIter->second[i].imagedatatype == MaCI::Image::KImageDataJPEG){
       
      
        if(i == 0){
          //        dPrint(1,"0");
          sprintf(wholeFileName,"%s/%.6d_%.6d.jpg",
                  iDirectory,timestamp.timestamp_s,timestamp.timestamp_us);
        }else{
          //dPrint(1,"%d",i);
          sprintf(wholeFileName,"%s/%d/%.6d_%.6d.jpg",
                  iDirectory, i,timestamp.timestamp_s,timestamp.timestamp_us);
        }
        
        
        //Open file and save it to buffer
        
        FILE *imageFile = fopen(wholeFileName, "rb");
        dPrint(10,"Trying to open file '%s'",wholeFileName);
        assert(imageFile != NULL);
        b = fread(buffer,iter->second[i],1,imageFile);
        fclose(imageFile);
        assert(b==1);
        
        // Only using Decoder for determining the image size.
        CJPEGDecoder d(buffer, iter->second[i]);
        const int w = d.GetImageWidth();
        const int h = d.GetImageHeight();
        
        dPrint(10,"Image found. Image is '%d x %d'.", w, h);
        // Add to container.
        idc.SetImageData((const unsigned char *)buffer, 
                         iter->second[i], 
                         KImageDataJPEG,
                         w, h, 
                         KImageDataUnknown,
                         true); // COPY!
      }else if(imageInfoIter->second[i].imagedatatype == MaCI::Image::KImageDataPNG){
        
        if(i == 0){
          //        dPrint(1,"0");
          sprintf(wholeFileName,"%s/%.6d_%.6d.png",
                  iDirectory,timestamp.timestamp_s,timestamp.timestamp_us);
        }else{
          //dPrint(1,"%d",i);
          sprintf(wholeFileName,"%s/%d/%.6d_%.6d.png",
                  iDirectory, i,timestamp.timestamp_s,timestamp.timestamp_us);
        }
        //Open file and save it to buffer
        
        FILE *imageFile = fopen(wholeFileName, "rb");
        dPrint(10,"Trying to open file '%s'",wholeFileName);
        assert(imageFile != NULL);
        b = fread(buffer,iter->second[i],1,imageFile);
        fclose(imageFile);
        assert(b==1);
        // Only using Decoder for determining the image size.
        const int w = imageInfoIter->second[i].imagewidth;
        const int h = imageInfoIter->second[i].imageheight;
        dPrint(10,"Image found. Image is '%d x %d'.", w, h);
        // Add to container.
        idc.SetImageData((const unsigned char *)buffer, 
                         iter->second[i], 
                         KImageDataPNG,
                         w, h, 
                         KImageDataUnknown,
                         true); // COPY!
      }else{

        dPrint(1,"ERROR. DON'T KNOW HOW TO HANDLE THIS TYPE OF IMAGES (type %u)",
               imageInfoIter->second[i].imagedatatype);
      }



      r &= id.AddImage(0, idc);
      assert(r == true);

    }
    e = iImageServer->SendImageData(id);
    return (e==MaCI::KMaCIOK);
  }else{
    
    return false;
  }
  
}
//*****************************************************************************

bool ImageFilePlayer::GetTimes(std::list<gim::time> *aTimes)
{
  
  aTimes->assign(iTimes.begin(),iTimes.end());
  return true;
}

//*****************************************************************************

std::string ImageFilePlayer::GetName(void)
{
  return iName;

}
//*****************************************************************************

void ImageFilePlayer::GetTimeLimits(gim::time &aBegin,gim::time &aEnd)
{
  aBegin = iBegin;
  aEnd = iEnd;
  dPrint(15,"begin %s, end %s",aBegin.toString().c_str(),aEnd.toString().c_str());
}
//*****************************************************************************







